/*
 Copyright (C) 1996-1997 GX Media, Inc.

 This program is free software; you can redistribute it and/or
 modify it under the terms of the GNU General Public License
 as published by the Free Software Foundation; either version 2
 of the License, or (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

 See the GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

 */

#include "stdafx.h"
#include "Sin.h"
#include "Entity.h"
#include "Texture.h"
#include "LCommon.h"
#include "QDraw.h"
#include "QMainFrame.h"
#include "ProgressWindow.h"

Sin::Sin(void) :
	Game(GetNumUtils())
{
	gameName = wxT("Sin");
	palDef = wxT("");
	defTexture = wxT("aqueduct/wl_aqd_58");
	texExt = wxT(".swl");

	cfg = new LConfig(gameName);
	QDraw::OutputText(_("Loading %s settings... "), gameName.c_str());

	gameDir = wxT("");
	cfg->RegisterVar(wxT("GameDir"), &gameDir, LVAR_WXSTR);

	setPIndex = 0;
	cfg->RegisterVar(wxT("SetParamIndex"), &setPIndex, LVAR_INT);

	runUtilsFlag = 0x0001;
	cfg->RegisterVar(wxT("RunUtils"), &runUtilsFlag, LVAR_INT);

	// QBSP3.
	utilsPath.resize(4);
	utilsParams.resize(4);
	utilsPath[0].Printf(wxT("%s/bin/"), LFile::GetInitDir().c_str());
	cfg->RegisterVar(wxT("UtilPath1"), &utilsPath[0], LVAR_WXSTR);

	utilsParams[0] = wxT("%file%");
	cfg->RegisterVar(wxT("UtilParam1"), &utilsParams[0], LVAR_WXSTR);

	// QVIS3
	utilsPath[1].Printf(wxT("%s/bin/"), LFile::GetInitDir().c_str());
	cfg->RegisterVar(wxT("UtilPath2"), &utilsPath[1], LVAR_WXSTR);

	utilsParams[1] = wxT("%file%");
	cfg->RegisterVar(wxT("UtilParam2"), &utilsParams[1], LVAR_WXSTR);

	// QRAD3
	utilsPath[2].Printf(wxT("%s/bin/"), LFile::GetInitDir().c_str());
	cfg->RegisterVar(wxT("UtilPath3"), &utilsPath[2], LVAR_WXSTR);

	utilsParams[2] = wxT("%file%");
	cfg->RegisterVar(wxT("UtilParam3"), &utilsParams[2], LVAR_WXSTR);

	// Sin.
	utilsPath[3] = wxT("sin.exe");
	cfg->RegisterVar(wxT("GamePath"), &utilsPath[3], LVAR_WXSTR);

	utilsParams[3] = wxT("+map %file%");
	cfg->RegisterVar(wxT("GameParam"), &utilsParams[3], LVAR_WXSTR);

	QDraw::OutputText(_("OK.\n"));
}

Sin::~Sin(void)
{
	cfg->SaveVars();
	delete cfg;
}

bool Sin::Init(void)
{
	if (initialized)
		return true;

	if (gameDir.empty() || !LFile::ExistDir(gameDir))
	{
		wxDirDialog dirDialog(GetMainFrame(), _("Locate Sin Folder"));

		if(dirDialog.ShowModal() != wxID_OK)
			return false;

		gameDir = dirDialog.GetPath();
	}

	baseDir.Printf(wxT("%s/base"), gameDir.c_str());
	mapDir.Printf(wxT("%s/maps"), baseDir.c_str());

	texDB = new TexDB(this);

	texDir.Printf(wxT("%s/textures"), baseDir.c_str());
	texDB->AddTexDir(texDir);
	/*
	 texDB->AddTexDir(pak0File);
	 texDB->AddTexDir(pak1File);
	 */

	initialized = true;

	wxString pak0File;
	wxString pak1File;

	pak0File.Printf(wxT("%s/pak0.sin"), baseDir.c_str());
	pak1File.Printf(wxT("%s/pak2.sin"), baseDir.c_str());

	LFile::UseDir(baseDir);
	pak0 = LFile::UsePak(pak0File);
	pak1 = LFile::UsePak(pak1File);

	/*
	 // dump .texs
	 for(int j = 0; j < 2; j++) {
	 LPak *pak;
	 char pakName[256];
	 if(j == 0) {
	 pak = pak0;
	 strcpy(pakName, "pak0.sin");
	 }
	 else {
	 pak = pak1;
	 strcpy(pakName, "pak2.sin");
	 }
	 for(int i = 0; i < pak->entries; i++) {
	 char swl[256];
	 strcpy(swl, pak->entry[i].filename);
	 strcat(swl, "\r\n");
	 if(!strstr(swl, ".swl"))
	 continue;

	 char dir[256];
	 char *c = strchr(swl, '/');
	 if(!c)
	 continue;
	 strcpy(dir, c + 1);
	 c = strchr(dir, '/');
	 if(!c)
	 continue;
	 *c = '\0';

	 char tex[256];
	 sprintf(tex, "TexLists\\Sin\\%s.tex", dir);
	 LFile sin;
	 sin.Open(tex, LFILE_APPEND);

	 char out[256];
	 //		sprintf(out, "%s\\%s", pakName, swl);

	 c = strchr(swl, '/');
	 strcpy(out, c + 1);

	 sin.Write(out, strlen(out));
	 }
	 }
	 */

	if (!LFile::ExistDir(texDir))
		ExtractTextures();

	// Verify game exe.
	if (!LFile::Exist(utilsPath[GetNumUtils() - 1]))
		utilsPath[GetNumUtils() - 1].Printf(wxT("%s/sin.exe"), gameDir.c_str());

	return true;
}

WireFrameGeom *
Sin::LoadModel(const wxString &filename)
{
	return NULL;
}

#define SIN_PALETTE_SIZE 256*4
#define MIPLEVELS 4

struct sinmiptex_t
{
	char name[64];
	int width, height;
	unsigned char palette[SIN_PALETTE_SIZE];
	short palcrc;
	int offsets[MIPLEVELS]; // four mip maps stored
	char animname[64]; // next frame in animation chain
	int flags;
	int contents;
	short value;
	short direct;
	float animtime;
	float nonlit;
	short directangle;
	short trans_angle;
	float directstyle;
	float translucence;
	float friction;
	float restitution;
	float trans_mag;
	float color[3];
};

bool Sin::LoadTexture(Texture *texture, const wxString &filename, int offset)
{
	sinmiptex_t header;
	int size, size2;
	int i;

	LFile file;
	QDraw::OutputText(_("Loading texture: %s... "), texture->GetName().c_str());

	if (!file.Open(filename))
	{
		QDraw::OutputText(_("Error. Couldn't open the file.\n"));
		return false;
	}

	file.Seek(offset);
	file.Read(&header, sizeof(header), 1);

	if (header.width <= 0 || header.width > 1024)
	{
		QDraw::OutputText(_("Error. The texture width is erroneous.\n"), filename.c_str());
		return false;
	}
	if (header.height <= 0 || header.height > 1024)
	{
		QDraw::OutputText(_("Error. The texture height is erroneous.\n"), filename.c_str());
		return false;
	}

	size = header.width * header.height;
	size2 = size * 2;

	unsigned char *mip[4];

	texture->mips = 4;

	mip[0] = (unsigned char *) malloc(size);
	mip[1] = (unsigned char *) malloc(size / 4);
	mip[2] = (unsigned char *) malloc(size / 16);
	mip[3] = (unsigned char *) malloc(size / 64);

	file.Seek(offset + header.offsets[0]);
	file.Read(mip[0], size, 1);
	file.Seek(offset + header.offsets[1]);
	file.Read(mip[1], size / 4, 1);
	file.Seek(offset + header.offsets[2]);
	file.Read(mip[2], size / 16, 1);
	file.Seek(offset + header.offsets[3]);
	file.Read(mip[3], size / 64, 1);

	unsigned short pal565[256];
	for (i = 0; i < 256; i++)
	{
		int r, g, b;

		r = header.palette[i * 4 + 0];
		g = header.palette[i * 4 + 1];
		b = header.palette[i * 4 + 2];

		LPalette::GammaCorrect(r, g, b, QDraw::textureGamma);

		pal565[i] = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
	}

	texture->mip[0] = malloc(size2);
	texture->mip[1] = malloc(size2 / 4);
	texture->mip[2] = malloc(size2 / 16);
	texture->mip[3] = malloc(size2 / 64);

	unsigned char *src;
	unsigned short *dst;

	for (int m = 0; m < 4; m++)
	{
		src = mip[m];
		dst = (unsigned short *) texture->mip[m];
		for (i = 0; i < size / (1 << (m * 2)); i++)
			*dst++ = pal565[*src++];
	}

	free(mip[0]);
	free(mip[1]);
	free(mip[2]);
	free(mip[3]);

	texture->surface = texture->mip[0];

	texture->realWidth = header.width;
	texture->realHeight = header.height;
	texture->bits = 16;

	return true;
}

void Sin::ExtractTextures(void)
{
	wxString texdir;
	texdir.Printf(wxT("%s/textures"), baseDir.c_str());

	static bool beenHere = false;
	if (beenHere)
		return;
	beenHere = true;

	wxString text;
	text.Printf(_("Some Sin textures not found.  Qoole 99 can extract them\n"
				  "to '%s' for you.  Do that now?"), texdir.c_str());
	if(wxMessageBox(text, _("Extract Textures"), wxYES_NO, GetMainFrame()) != wxID_YES)
		return;

	wxString outname;
	wxString dirname;
	char *name, *c;
	int i, count = 0, total = 0;

	for (i = 0; i < pak0->entries; i++)
		if (strstr(pak0->entry[i].filename, ".swl"))
			total++;
	for (i = 0; i < pak1->entries; i++)
		if (strstr(pak1->entry[i].filename, ".swl"))
			total++;

	ProgressFunc prog(_("Progress"), _("Extracting Textures"));
	wxSetCursor(wxCURSOR_WAIT);

	for (int j = 0; j < 2; j++)
	{
		LPak *pak = j ? pak1 : pak0;
		for (i = 0; i < pak->entries; i++)
		{
			name = pak->entry[i].filename;
			if (strstr(name, ".swl"))
			{
				outname.Printf(wxT("%s/%s"), baseDir.c_str(),
						wxString(name, wxConvUTF8).c_str());
				dirname = wxFileName(outname).GetPath();

				LFile::MakeDir(dirname);
				LFile::Extract(wxString(name, wxConvUTF8), outname);

				ProgressFunc::SetPos(count++ * 100 / total);
			}
		}
	}

	wxSetCursor(wxCURSOR_ARROW);
}

// Game Map Compile Stuff.
const wxString &Sin::GetUtilName(int index) const
{
	static wxString utilNames[] =
	{ wxT("SinQBSP3"), wxT("SinQVis3"), wxT("SinQRad3"), wxT("Sin") };
	ASSERT(index >= 0 && index < 4);
	return utilNames[index];
}
